using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Timing;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.Caching;
using System.Text.Json;
using Matrix.Notification.Application.Logging;
using Matrix.Notification.Domain.Notifications;
using Matrix.Notification.Channels;

namespace Matrix.Notification.Services
{
    /// <summary>
    /// 默认通知管理器实现
    /// </summary>
    public class DefaultNotificationManager : INotificationManager, ITransientDependency
    {
        private readonly ILogger<DefaultNotificationManager> _logger;
        private readonly IClock _clock;
        private readonly IBackgroundJobManager _backgroundJobManager;
        private readonly IDistributedCache _cache;
        private readonly NotificationManagerOptions _options;
        private readonly IEnumerable<INotificationChannel> _channels;
        private readonly INotificationRoutingService _routingService;

        public DefaultNotificationManager(
            ILogger<DefaultNotificationManager> logger,
            IClock clock,
            IBackgroundJobManager backgroundJobManager,
            IDistributedCache cache,
            IOptions<NotificationManagerOptions> options,
            IEnumerable<INotificationChannel> channels,
            INotificationRoutingService routingService)
        {
            _logger = logger;
            _clock = clock;
            _backgroundJobManager = backgroundJobManager;
            _cache = cache;
            _options = options.Value;
            _channels = channels;
            _routingService = routingService;
        }

        public async Task<NotificationSendResult> SendAsync(
            NotificationMessage message,
            IEnumerable<NotificationChannel>? channels = null,
            CancellationToken cancellationToken = default)
        {
            var startTime = _clock.Now;
            var result = new NotificationSendResult
            {
                NotificationId = message.Id,
                TotalCount = 1,
                SentTime = startTime
            };

            try
            {
                _logger.LogInformation("开始发送通知: Id={Id}, Type={Type}, Channels={Channels}",
                    message.Id, message.Type, string.Join(",", channels?.ToArray() ?? new object[0]));

                // 确定发送渠道
                var targetChannels = channels?.ToList() ?? await _routingService.GetOptimalChannelsAsync(message, cancellationToken);

                if (!targetChannels.Any())
                {
                    result.IsSuccess = false;
                    result.ErrorMessage = "没有可用的通知渠道";
                    _logger.LogWarning("通知发送失败：没有可用的通知渠道: Id={Id}", message.Id);
                    return result;
                }

                // 更新通知状态
                await UpdateNotificationStatusAsync(message.Id, NotificationStatusValue.Sending);

                // 并行发送到各渠道
                var sendTasks = targetChannels.Select(async channel =>
                {
                    try
                    {
                        var channelMessage = CreateChannelMessage(message, channel);
                        var channelResult = await channel.SendAsync(channelMessage, cancellationToken);

                        return new ChannelSendResult
                        {
                            Channel = channel,
                            IsSuccess = channelResult.IsSuccess,
                            SentCount = 1,
                            SuccessCount = channelResult.IsSuccess ? 1 : 0,
                            FailureCount = channelResult.IsSuccess ? 0 : 1,
                            ErrorMessage = channelResult.ErrorMessage,
                            DurationMs = channelResult.SentAt > startTime ? (long)(channelResult.SentAt - startTime).TotalMilliseconds : 0
                        };
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, "渠道发送失败: Channel={Channel}, NotificationId={NotificationId}",
                            channel, message.Id);

                        return new ChannelSendResult
                        {
                            Channel = channel,
                            IsSuccess = false,
                            SentCount = 1,
                            SuccessCount = 0,
                            FailureCount = 1,
                            ErrorMessage = ex.Message,
                            DurationMs = (long)(_clock.Now - startTime).TotalMilliseconds
                        };
                    }
                });

                var channelResults = await Task.WhenAll(sendTasks);

                // 汇总结果
                foreach (var channelResult in channelResults)
                {
                    result.ChannelResults[channelResult.Channel] = channelResult;
                    result.SuccessCount += channelResult.SuccessCount;
                    result.FailureCount += channelResult.FailureCount;
                }

                result.IsSuccess = result.FailureCount == 0;
                result.DurationMs = (long)(_clock.Now - startTime).TotalMilliseconds;

                // 更新最终状态
                var finalStatus = result.IsSuccess ? NotificationStatusValue.Success :
                    (result.SuccessCount > 0 ? NotificationStatusValue.PartialSuccess : NotificationStatusValue.Failed);

                await UpdateNotificationStatusAsync(message.Id, finalStatus);

                _logger.LogInformation(
                    "通知发送完成: Id={Id}, Success={Success}, Total={Total}, Duration={Duration}ms",
                    message.Id, result.SuccessCount, result.TotalCount, result.DurationMs);

                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "通知发送异常: Id={Id}", message.Id);

                result.IsSuccess = false;
                result.ErrorMessage = ex.Message;
                result.DurationMs = (long)(_clock.Now - startTime).TotalMilliseconds;

                await UpdateNotificationStatusAsync(message.Id, NotificationStatusValue.Failed);
                return result;
            }
        }

        public async Task<NotificationSendResult> SendBatchAsync(
            IEnumerable<NotificationMessage> messages,
            IEnumerable<NotificationChannel>? channels = null,
            CancellationToken cancellationToken = default)
        {
            var startTime = _clock.Now;
            var messageList = messages.ToList();
            var result = new NotificationSendResult
            {
                NotificationId = Guid.NewGuid().ToString(),
                TotalCount = messageList.Count,
                SentTime = startTime
            };

            try
            {
                _logger.LogInformation("开始批量发送通知: Count={Count}", messageList.Count);

                // 按渠道分组消息
                var targetChannels = channels?.ToList() ?? await _routingService.GetOptimalChannelsForBatchAsync(messageList, cancellationToken);

                if (!targetChannels.Any())
                {
                    result.IsSuccess = false;
                    result.ErrorMessage = "没有可用的通知渠道";
                    return result;
                }

                // 并行发送到各渠道
                var channelTasks = targetChannels.Select(async channel =>
                {
                    try
                    {
                        var channelMessages = messageList.Select(msg => CreateChannelMessage(msg, channel)).ToList();
                        var channelResult = await channel.SendBatchAsync(channelMessages, cancellationToken);

                        return new ChannelSendResult
                        {
                            Channel = channel,
                            IsSuccess = channelResult.IsSuccess,
                            SentCount = channelMessages.Count,
                            SuccessCount = channelResult.IsSuccess ? channelMessages.Count : 0,
                            FailureCount = channelResult.IsSuccess ? 0 : channelResult.FailureCount,
                            ErrorMessage = channelResult.ErrorMessage,
                            DurationMs = (long)(_clock.Now - startTime).TotalMilliseconds
                        };
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, "批量渠道发送失败: Channel={Channel}", channel);

                        return new ChannelSendResult
                        {
                            Channel = channel,
                            IsSuccess = false,
                            SentCount = messageList.Count,
                            SuccessCount = 0,
                            FailureCount = messageList.Count,
                            ErrorMessage = ex.Message,
                            DurationMs = (long)(_clock.Now - startTime).TotalMilliseconds
                        };
                    }
                });

                var channelResults = await Task.WhenAll(channelTasks);

                // 汇总结果
                foreach (var channelResult in channelResults)
                {
                    result.ChannelResults[channelResult.Channel] = channelResult;
                    result.SuccessCount += channelResult.SuccessCount;
                    result.FailureCount += channelResult.FailureCount;
                }

                result.IsSuccess = result.FailureCount == 0;
                result.DurationMs = (long)(_clock.Now - startTime).TotalMilliseconds;

                _logger.LogInformation(
                    "批量通知发送完成: Total={Total}, Success={Success}, Failed={Failed}, Duration={Duration}ms",
                    result.TotalCount, result.SuccessCount, result.FailureCount, result.DurationMs);

                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "批量通知发送异常");

                result.IsSuccess = false;
                result.ErrorMessage = ex.Message;
                result.DurationMs = (long)(_clock.Now - startTime).TotalMilliseconds;
                return result;
            }
        }

        public async Task<NotificationSendResult> SendToUserAsync(
            NotificationMessage message,
            Guid userId,
            CancellationToken cancellationToken = default)
        {
            try
            {
                // 获取用户通知偏好
                var userPreferences = await GetUserNotificationPreferencesAsync(userId, cancellationToken);

                // 根据偏好选择渠道
                var preferredChannels = userPreferences.PreferredChannels
                    .Where(ch => userPreferences.IsEnabled(ch))
                    .ToList();

                if (!preferredChannels.Any())
                {
                    // 如果用户没有偏好，使用默认渠道
                    preferredChannels = await _routingService.GetOptimalChannelsAsync(message, cancellationToken);
                }

                _logger.LogInformation("根据用户偏好发送通知: UserId={UserId}, PreferredChannels={Channels}",
                    userId, string.Join(",", preferredChannels));

                return await SendAsync(message, preferredChannels, cancellationToken);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "根据用户偏好发送通知失败: UserId={UserId}, NotificationId={NotificationId}",
                    userId, message.Id);

                // 降级到默认发送方式
                return await SendAsync(message, null, cancellationToken);
            }
        }

        public async Task<NotificationSendResult> SendToUsersAsync(
            NotificationMessage message,
            IEnumerable<Guid> userIds,
            CancellationToken cancellationToken = default)
        {
            var userIdList = userIds.ToList();
            var results = new List<NotificationSendResult>();

            _logger.LogInformation("向多个用户发送通知: UserCount={UserCount}, NotificationId={NotificationId}",
                userIdList.Count, message.Id);

            // 分批处理，避免同时发送太多
            const int batchSize = 100;
            for (int i = 0; i < userIdList.Count; i += batchSize)
            {
                var batchUserIds = userIdList.Skip(i).Take(batchSize);
                var batchTasks = batchUserIds.Select(userId => SendToUserAsync(message, userId, cancellationToken));
                var batchResults = await Task.WhenAll(batchTasks);
                results.AddRange(batchResults);
            }

            // 汇总所有结果
            var totalResult = new NotificationSendResult
            {
                NotificationId = message.Id,
                TotalCount = userIdList.Count,
                SuccessCount = results.Sum(r => r.SuccessCount),
                FailureCount = results.Sum(r => r.FailureCount),
                IsSuccess = results.All(r => r.IsSuccess),
                SentTime = results.Min(r => r.SentTime),
                DurationMs = (long)(_clock.Now - results.Min(r => r.SentTime)).TotalMilliseconds
            };

            if (!totalResult.IsSuccess)
            {
                totalResult.ErrorMessage = "部分用户通知发送失败";
            }

            return totalResult;
        }

        public async Task<string> SendDelayedAsync(
            NotificationMessage message,
            DateTime scheduledTime,
            IEnumerable<NotificationChannel>? channels = null,
            CancellationToken cancellationToken = default)
        {
            try
            {
                var taskId = Guid.NewGuid().ToString();
                var delay = scheduledTime > _clock.Now ? scheduledTime - _clock.Now : TimeSpan.Zero;

                _logger.LogInformation(
                    "安排延迟通知发送: NotificationId={NotificationId}, ScheduledTime={ScheduledTime}, Delay={Delay}分钟",
                    message.Id, scheduledTime, delay.TotalMinutes);

                await _backgroundJobManager.EnqueueAsync(
                    new DelayedNotificationJobArgs
                    {
                        TaskId = taskId,
                        Message = message,
                        Channels = channels?.ToList(),
                        ScheduledTime = scheduledTime
                    },
                    BackgroundJobPriority.Low,
                    delay: delay,
                    cancellationToken: cancellationToken);

                return taskId;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "安排延迟通知发送失败: NotificationId={NotificationId}", message.Id);
                throw;
            }
        }

        public async Task<List<NotificationChannelInfo>> GetAvailableChannelsAsync(
            CancellationToken cancellationToken = default)
        {
            var channelInfos = new List<NotificationChannelInfo>();

            foreach (var channel in _channels)
            {
                try
                {
                    var isAvailable = await channel.IsAvailableAsync(cancellationToken);
                    var channelInfo = new NotificationChannelInfo
                    {
                        Channel = Enum.Parse<NotificationChannel>(channel.ChannelType),
                        Name = channel.ChannelType,
                        Description = GetChannelDescription(channel.ChannelType),
                        IsAvailable = isAvailable,
                        IsEnabled = _options.ChannelConfigs.GetValueOrDefault(channel.ChannelType, new ChannelConfig { IsEnabled = true }).IsEnabled,
                        SupportedTypes = GetSupportedNotificationTypes(channel.ChannelType),
                        EstimatedLatencyMs = GetEstimatedLatency(channel.ChannelType),
                        ReliabilityScore = GetReliabilityScore(channel.ChannelType),
                        ConfigStatus = GetConfigurationStatus(channel.ChannelType)
                    };

                    channelInfos.Add(channelInfo);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "检查渠道可用性失败: Channel={Channel}", channel.ChannelType);
                }
            }

            return channelInfos.OrderByDescending(c => c.ReliabilityScore).ToList();
        }

        public async Task<NotificationStatus?> GetStatusAsync(
            string notificationId,
            CancellationToken cancellationToken = default)
        {
            try
            {
                var cacheKey = $"notification_status:{notificationId}";
                var cachedStatus = await _cache.GetStringAsync(cacheKey, cancellationToken);

                if (!string.IsNullOrEmpty(cachedStatus))
                {
                    return JsonSerializer.Deserialize<NotificationStatus>(cachedStatus);
                }

                // 如果缓存中没有，返回基本状态
                return new NotificationStatus
                {
                    NotificationId = notificationId,
                    Status = NotificationStatusValue.Pending,
                    CreatedTime = _clock.Now,
                    LastUpdatedTime = _clock.Now
                };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取通知状态失败: NotificationId={NotificationId}", notificationId);
                return null;
            }
        }

        public async Task<bool> CancelAsync(
            string taskId,
            CancellationToken cancellationToken = default)
        {
            try
            {
                // 这里可以实现取消逻辑
                // ABP BackgroundJobs 可能不直接支持取消，可以通过数据库标记等方式实现

                _logger.LogInformation("取消延迟通知任务: TaskId={TaskId}", taskId);

                // 实际实现中，应该根据taskId在数据库中查找并标记为取消
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "取消延迟通知任务失败: TaskId={TaskId}", taskId);
                return false;
            }
        }

        #region 私有方法

        private object CreateChannelMessage(NotificationMessage message, NotificationChannel channel)
        {
            return channel switch
            {
                NotificationChannel.Email => new EmailNotificationMessage
                {
                    Id = Guid.Parse(message.Id),
                    CreationTime = message.CreationTime,
                    To = message.Recipients.FirstOrDefault()?.Email ?? "",
                    Subject = message.Title,
                    HtmlBody = message.Content,
                    TextBody = StripHtml(message.Content)
                },
                NotificationChannel.Push => new PushNotificationMessage
                {
                    Id = message.Id,
                    Title = message.Title,
                    Body = message.Content,
                    Data = message.Data,
                    Timestamp = _clock.Now
                },
                NotificationChannel.WebHook => new WebHookNotificationMessage
                {
                    Id = message.Id,
                    Title = message.Title,
                    Content = message.Content,
                    ContentType = "application/json",
                    Method = System.Net.Http.HttpMethod.Post,
                    WebHookUrl = GetDefaultWebHookUrl(),
                    Data = new Dictionary<string, object>
                    {
                        ["notificationId"] = message.Id,
                        ["title"] = message.Title,
                        ["content"] = message.Content,
                        ["timestamp"] = message.CreationTime,
                        ["data"] = message.Data ?? new Dictionary<string, object>()
                    }
                },
                _ => throw new NotSupportedException($"不支持的通知渠道: {channel}")
            };
        }

        private async Task UpdateNotificationStatusAsync(string notificationId, NotificationStatusValue status)
        {
            try
            {
                var notificationStatus = new NotificationStatus
                {
                    NotificationId = notificationId,
                    Status = status,
                    CreatedTime = _clock.Now,
                    LastUpdatedTime = _clock.Now
                };

                var cacheKey = $"notification_status:{notificationId}";
                var json = JsonSerializer.Serialize(notificationStatus);

                await _cache.SetStringAsync(
                    cacheKey,
                    json,
                    new DistributedCacheEntryOptions
                    {
                        AbsoluteExpirationRelativeToNow = TimeSpan.FromDays(7)
                    });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "更新通知状态失败: NotificationId={NotificationId}, Status={Status}",
                    notificationId, status);
            }
        }

        private async Task<UserNotificationPreferences> GetUserNotificationPreferencesAsync(Guid userId, CancellationToken cancellationToken)
        {
            var cacheKey = $"user_notification_preferences:{userId}";
            var cached = await _cache.GetStringAsync(cacheKey, cancellationToken);

            if (!string.IsNullOrEmpty(cached))
            {
                return JsonSerializer.Deserialize<UserNotificationPreferences>(cached)!;
            }

            // 返回默认偏好
            var preferences = new UserNotificationPreferences
            {
                UserId = userId,
                PreferredChannels = new List<NotificationChannel>
                {
                    NotificationChannel.Email,
                    NotificationChannel.Push
                },
                ChannelSettings = new Dictionary<NotificationChannel, ChannelSetting>
                {
                    [NotificationChannel.Email] = new ChannelSetting { IsEnabled = true, QuietHours = null },
                    [NotificationChannel.Push] = new ChannelSetting { IsEnabled = true, QuietHours = null }
                }
            };

            await _cache.SetStringAsync(
                cacheKey,
                JsonSerializer.Serialize(preferences),
                new DistributedCacheEntryOptions
                {
                    AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1)
                },
                cancellationToken);

            return preferences;
        }

        private string GetChannelDescription(string channelType)
        {
            return channelType switch
            {
                "Email" => "电子邮件通知",
                "Push" => "推送通知",
                "WebHook" => "WebHook回调通知",
                "SMS" => "短信通知",
                _ => "未知渠道"
            };
        }

        private List<NotificationType> GetSupportedNotificationTypes(string channelType)
        {
            // 所有渠道都支持所有类型，可以根据实际情况调整
            return Enum.GetValues<NotificationType>().ToList();
        }

        private int GetEstimatedLatency(string channelType)
        {
            return channelType switch
            {
                "Email" => 5000,      // 5秒
                "Push" => 1000,       // 1秒
                "WebHook" => 2000,    // 2秒
                "SMS" => 3000,        // 3秒
                _ => 5000
            };
        }

        private int GetReliabilityScore(string channelType)
        {
            return channelType switch
            {
                "Email" => 85,        // 邮件相对可靠
                "Push" => 75,         // 推送可能被拦截
                "WebHook" => 90,      // WebHook最可控
                "SMS" => 95,          // 短信最可靠
                _ => 50
            };
        }

        private ConfigurationStatus GetConfigurationStatus(string channelType)
        {
            // 这里应该检查实际的配置状态
            // 暂时返回已配置状态
            return ConfigurationStatus.Configured;
        }

        private string StripHtml(string html)
        {
            if (string.IsNullOrEmpty(html))
                return html;

            // 简单的HTML标签移除
            return System.Text.RegularExpressions.Regex.Replace(html, "<[^>]*>", "");
        }

        private string GetDefaultWebHookUrl()
        {
            return _options.DefaultWebHookUrl ?? "https://example.com/webhook";
        }

        #endregion
    }

    #region 后台任务

    /// <summary>
    /// 延迟通知发送任务参数
    /// </summary>
    public class DelayedNotificationJobArgs
    {
        public string TaskId { get; set; } = string.Empty;
        public NotificationMessage Message { get; set; } = null!;
        public List<NotificationChannel>? Channels { get; set; }
        public DateTime ScheduledTime { get; set; }
    }

    /// <summary>
    /// 延迟通知发送后台任务
    /// </summary>
    public class DelayedNotificationJob : AsyncBackgroundJob<DelayedNotificationJobArgs>
    {
        private readonly INotificationManager _notificationManager;
        private readonly ILogger<DelayedNotificationJob> _logger;

        public DelayedNotificationJob(
            INotificationManager notificationManager,
            ILogger<DelayedNotificationJob> logger)
        {
            _notificationManager = notificationManager;
            _logger = logger;
        }

        public override async Task ExecuteAsync(DelayedNotificationJobArgs args)
        {
            try
            {
                _logger.LogInformation(
                    "执行延迟通知发送任务: TaskId={TaskId}, NotificationId={NotificationId}",
                    args.TaskId, args.Message.Id);

                await _notificationManager.SendAsync(args.Message, args.Channels);

                _logger.LogInformation(
                    "延迟通知发送任务完成: TaskId={TaskId}, NotificationId={NotificationId}",
                    args.TaskId, args.Message.Id);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex,
                    "延迟通知发送任务失败: TaskId={TaskId}, NotificationId={NotificationId}",
                    args.TaskId, args.Message.Id);
            }
        }
    }

    #endregion

    #region 配置和模型

    /// <summary>
    /// 通知管理器选项
    /// </summary>
    public class NotificationManagerOptions
    {
        /// <summary>
        /// 默认WebHook URL
        /// </summary>
        public string? DefaultWebHookUrl { get; set; }

        /// <summary>
        /// 渠道配置
        /// </summary>
        public Dictionary<string, ChannelConfig> ChannelConfigs { get; set; } = new();

        /// <summary>
        /// 最大并发发送数量
        /// </summary>
        public int MaxConcurrentSends { get; set; } = 50;

        /// <summary>
        /// 批量发送大小
        /// </summary>
        public int BatchSize { get; set; } = 100;

        /// <summary>
        /// 重试次数
        /// </summary>
        public int RetryCount { get; set; } = 3;

        /// <summary>
        /// 启用智能路由
        /// </summary>
        public bool EnableSmartRouting { get; set; } = true;
    }

    /// <summary>
    /// 渠道配置
    /// </summary>
    public class ChannelConfig
    {
        /// <summary>
        /// 是否启用
        /// </summary>
        public bool IsEnabled { get; set; } = true;

        /// <summary>
        /// 优先级
        /// </summary>
        public int Priority { get; set; } = 1;

        /// <summary>
        /// 权重
        /// </summary>
        public double Weight { get; set; } = 1.0;

        /// <summary>
        /// 最大重试次数
        /// </summary>
        public int MaxRetryCount { get; set; } = 3;
    }

    /// <summary>
    /// 用户通知偏好
    /// </summary>
    public class UserNotificationPreferences
    {
        public Guid UserId { get; set; }
        public List<NotificationChannel> PreferredChannels { get; set; } = new();
        public Dictionary<NotificationChannel, ChannelSetting> ChannelSettings { get; set; } = new();

        public bool IsEnabled(NotificationChannel channel)
        {
            return ChannelSettings.TryGetValue(channel, out var setting) && setting.IsEnabled;
        }
    }

    /// <summary>
    /// 渠道设置
    /// </summary>
    public class ChannelSetting
    {
        public bool IsEnabled { get; set; } = true;
        public QuietHours? QuietHours { get; set; }
    }

    /// <summary>
    /// 免打扰时间
    /// </summary>
    public class QuietHours
    {
        public TimeSpan StartTime { get; set; }
        public TimeSpan EndTime { get; set; }
        public List<DayOfWeek> ApplicableDays { get; set; } = new();
    }

    /// <summary>
    /// 通知路由服务接口
    /// </summary>
    public interface INotificationRoutingService
    {
        Task<List<NotificationChannel>> GetOptimalChannelsAsync(
            NotificationMessage message,
            CancellationToken cancellationToken = default);

        Task<List<NotificationChannel>> GetOptimalChannelsForBatchAsync(
            List<NotificationMessage> messages,
            CancellationToken cancellationToken = default);
    }

    #endregion
}